package edu.xidian.onlinedocument.handler.interceptor;

import edu.xidian.onlinedocument.handler.AttributeName;
import edu.xidian.onlinedocument.handler.excpetions.custom.CustomException;
import edu.xidian.onlinedocument.service.UserService;
import edu.xidian.onlinedocument.views.ResultCode;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * Interceptor拦截器，用于token验证
 *
 * 其中token放在http请求的header中，命名为"token"
 * 可参考这篇博客：https://my.oschina.net/bianxin/blog/2876640
 * 以及路径的配置：https://www.cnblogs.com/zktww/p/11550891.html
 */
public class CheckTokenInterceptor implements HandlerInterceptor {

    private final Logger logger = LoggerFactory.getLogger(CheckTokenInterceptor.class);

    private final UserService userService;

    @Autowired
    public CheckTokenInterceptor(UserService userService) {
        this.userService = userService;
    }

    /**
     * 在进入Servlet服务器之前拦截HTTP请求，进行内容解析和Token验证，成功时在Attribute中加入用户信息相关字段
     * @param request HTTP请求
     * @param response 即将返回的HTTP回应
     * @param handler 映射的接口
     * @return true / false: 成功 / 失败
     * @throws Exception 所有异常
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // System.out.println("check token interceptor, " + request.getMethod() + ", " + request.getRequestURI());
        // logger.info("request api: [{}] ", request.getRequestURI());

        // 如果不是映射到方法直接通过
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        // 方法注解级拦截器
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        // 判断接口是否需要检查token
        TokenCheck methodAnnotation = method.getAnnotation(TokenCheck.class);
        // 有 @TokenCheck 注解，需要认证
        if (methodAnnotation != null) {
            logger.info("request method is [{}], URL is [{}], with token", request.getMethod(), request.getRequestURL());
            // 从HTTP请求头中获取Token
            String token = request.getHeader(AttributeName.TOKEN_NAME);
            // 如果header中没有token字段，则报错
            if(StringUtils.isBlank(token)) {
                throw new CustomException(ResultCode.HTTP_HEADER_IS_NOT_EXIST_TOKEN);
            }
            // 这里不取token的字段，是因为不想用jwt的方式来处理，安全性差了点
            // String userNum = TokenUtil.getUserNum(token);
            // 如果有token字段，则到数据库中查找
            Integer userId = userService.getUserIdByUserToken(token);
            // 如果没有相应的user，则报错
            if(userId == null) {
                throw new CustomException(ResultCode.VERIFY_FAILED);
            }
            String userNum = userService.getUserDataByUserId(userId).getUserNum();
            // 将token对应的用户的id和num取出，注入到request里
            request.setAttribute(AttributeName.CLIENT_ID, userId);
            request.setAttribute(AttributeName.CLIENT_NUM, userNum);
        }
        else {
            logger.info("request method is [{}], URL is [{}], without token", request.getMethod(), request.getRequestURL());
        }
        return true;
    }
}
